import { Controller } from 'egg';
import * as sharp from 'sharp';
import * as sendToWormhole from 'stream-wormhole';
import { nanoid } from 'nanoid';
import { createWriteStream } from 'fs';
import { parse, join, extname } from 'path';
import { pipeline } from 'stream/promises';
import formatPath from '../utils/format-path';
import { FileStream } from 'egg';

export default class UtilsController extends Controller {
  splitIdAndUuid(str = '') {
    const result = { id: '', uuid: '' };
    if (!str) return result;
    const firstDashIndex = str.indexOf('-');
    if (firstDashIndex < 0) return result;
    result.id = str.slice(0, firstDashIndex);
    result.uuid = str.slice(firstDashIndex + 1);
    return result;
  }
  async renderH5Page() {
    const { ctx } = this;
    const { idAndUuid } = ctx.params;
    const query = this.splitIdAndUuid(idAndUuid);
    try {
      const { html, desc, title } = await ctx.service.utils.renderToPageData(query);
      await ctx.render('page.nj', { html, title, desc })
    } catch (e) {
      ctx.helper.error({ ctx, errorType: 'h5WorkNotExistError' });
    }

  }
  async uploadToOSS() {
    const { ctx } = this;
    const stream = await ctx.getFileStream();
    const savedOSSPath = join('test', nanoid(6) + extname(stream.filename));
    try {
      const result = await ctx.oss.put(savedOSSPath, stream);
      const { name, url } = result;
      return ctx.helper.success({ ctx, res: { name, url } });
    } catch (e) {
      console.error(e);
      await sendToWormhole(stream);
      ctx.helper.error({ ctx, errorType: 'imageUploadFail' });
    }
  }
  async uploadMutipleFiles() {
    const { ctx, app } = this;
    const { fileSize } = app.config.multipart;
    const parts = ctx.multipart({ limits: { fileSize: fileSize as number } });
    const urls: string[] = [];
    let part: FileStream | string[];
    while ((part = await parts())) {
      if (!Array.isArray(part)) {
        try {
          const savedOSSPath = join('test', nanoid(6) + extname(part.filename));
          const result = await ctx.oss.put(savedOSSPath, part);
          const { url } = result;
          urls.push(url);
          if (part.truncated) {
            await ctx.oss.delete(savedOSSPath);
            return ctx.helper.error({ ctx, errorType: 'imageUploadFileSizeError' });
          }
        } catch (e) {
          await sendToWormhole(part);
          ctx.helper.error({ ctx, errorType: 'imageUploadFail' });
        }
      }
    }
    ctx.helper.success({ ctx, res: { urls } });
  }
  async fileLocalUpload() {
    const { ctx, app } = this;
    const { filepath } = ctx.request.files[0];
    const imageSource = sharp(filepath);
    const metaData = await imageSource.metadata();
    let thumbnailUrl = '';
    if (metaData.width && metaData.width > 300) {
      const { name, ext, dir } = parse(filepath);
      const thumbnailFilePath = join(dir, `${name}-thumbnail${ext}`);
      await imageSource.resize({ width: 300 }).toFile(thumbnailFilePath);
      thumbnailUrl = thumbnailFilePath.replace(app.config.baseDir, app.config.baseUrl);
    }
    const url = filepath.replace(app.config.baseDir, app.config.baseUrl);
    ctx.helper.success({ ctx, res: { url: formatPath(url), thumbnailUrl: thumbnailUrl ? formatPath(thumbnailUrl) : url } });
  }
  pathToURL(path: string) {
    const { app } = this;
    return formatPath(path.replace(app.config.baseDir, app.config.baseUrl));
  }
  async fileUploadByStream() {
    const { ctx, app } = this;
    const stream = await ctx.getFileStream();
    const uid = nanoid(6);
    const savedFilePath = join(app.config.baseDir, 'uploads', uid + extname(stream.filename));
    const savedThumbnailPath = join(app.config.baseDir, 'uploads', uid + '_thumbnail' + extname(stream.filename));
    const target = createWriteStream(savedFilePath);
    const target2 = createWriteStream(savedThumbnailPath);
    const savePromise = pipeline(stream, target);
    const transformer = sharp().resize({ width: 300 });
    const thumbnailPromise = pipeline(stream, transformer, target2);
    try {
      await Promise.all([ savePromise, thumbnailPromise ]);
    } catch (e) {
      return ctx.helper.error({ ctx, errorType: 'imageUploadFail' });
    }
    ctx.helper.success({ ctx, res: { url: this.pathToURL(savedFilePath), thumbnailUrl: this.pathToURL(savedThumbnailPath) } });
  }
}
